# coding=UTF-8
import numpy as np
import pandas as pd
from scipy.spatial.distance import cosine, cityblock, jaccard, canberra, \
    euclidean, minkowski, braycurtis, hamming, kulsinski, chebyshev , \
    dice,yule,sokalmichener,russellrao,rogerstanimoto


#question1_vectors [100000,100]
#question2_vectors [100000,100]
def get_all_vector_distance(transformation_name, question1_vectors, question2_vectors):
    data = pd.DataFrame()
    data['cosine_distance_{}'.format(transformation_name)] = [np.nan_to_num(cosine(x, y)) for (x, y) in zip(np.nan_to_num(question1_vectors),
                                                                                             np.nan_to_num(question2_vectors))]

    data['cityblock_distance_{}'.format(transformation_name)] = [np.nan_to_num(np.log(cityblock(x, y)+1)) for (x, y) in zip(np.nan_to_num(question1_vectors),
                                                                                                   np.nan_to_num(question2_vectors))]

    data['jaccard_distance_{}'.format(transformation_name)] = [np.nan_to_num(jaccard(x, y)) for (x, y) in zip(np.nan_to_num(question1_vectors),
                                                                                               np.nan_to_num(question2_vectors))]

    data['canberra_distance_{}'.format(transformation_name)] = [np.nan_to_num(canberra(x, y)) for (x, y) in zip(np.nan_to_num(question1_vectors),
                                                                                                 np.nan_to_num(question2_vectors))]

    data['euclidean_distance_{}'.format(transformation_name)] = [np.nan_to_num(euclidean(x, y)) for (x, y) in zip(np.nan_to_num(question1_vectors),
                                                                                                   np.nan_to_num(question2_vectors))]

    data['minkowski_distance_{}'.format(transformation_name)] = [np.nan_to_num(minkowski(x, y, 3)) for (x, y) in zip(np.nan_to_num(question1_vectors),
                                                                                                      np.nan_to_num(question2_vectors))]

    data['hamming_distance_{}'.format(transformation_name)] = [np.nan_to_num(hamming(x, y)) for (x, y) in zip(np.nan_to_num(question1_vectors),
                                                                                               np.nan_to_num(question2_vectors))]
    data['kulsinski_distance_{}'.format(transformation_name)] = [np.nan_to_num(kulsinski(x, y)) for (x, y) in
                                                                 zip(np.nan_to_num(question1_vectors),
                                                                     np.nan_to_num(question2_vectors))]
    data['braycurtis_distance_{}'.format(transformation_name)] = [np.nan_to_num(braycurtis(x, y)) for (x, y) in
                                                                  zip(np.nan_to_num(question1_vectors),
                                                                      np.nan_to_num(question2_vectors))]
    data['chebyshev_distance_{}'.format(transformation_name)] = [np.nan_to_num(chebyshev(x, y)) for (x, y) in
                                                                 zip(np.nan_to_num(question1_vectors),
                                                                     np.nan_to_num(question2_vectors))]
    data['dice_distance_{}'.format(transformation_name)] = [np.nan_to_num(dice(x, y)) for (x, y) in
                                                                 zip(np.nan_to_num(question1_vectors),
                                                                     np.nan_to_num(question2_vectors))]
    data['yule_distance_{}'.format(transformation_name)] = [np.nan_to_num(yule(x, y)) for (x, y) in
                                                                 zip(np.nan_to_num(question1_vectors),
                                                                     np.nan_to_num(question2_vectors))]
    data['sokalmichener_distance_{}'.format(transformation_name)] = [np.nan_to_num(sokalmichener(x, y)) for (x, y) in
                                                                 zip(np.nan_to_num(question1_vectors),
                                                                     np.nan_to_num(question2_vectors))]
    data['russellrao_distance_{}'.format(transformation_name)] = [np.nan_to_num(russellrao(x, y)) for (x, y) in
                                                                 zip(np.nan_to_num(question1_vectors),
                                                                     np.nan_to_num(question2_vectors))]
    data['rogerstanimoto_distance_{}'.format(transformation_name)] = [np.nan_to_num(rogerstanimoto(x, y)) for (x, y) in
                                                                 zip(np.nan_to_num(question1_vectors),
                                                                     np.nan_to_num(question2_vectors))]
    return data

#vector1 [100]
#vector2 [100]
def get_two_vector_distance(vector1, vector2):
    if len(vector1)==0 or len(vector2)==0:
        return [0]*15
    return[
        np.nan_to_num(cosine(vector1, vector2)),
        np.nan_to_num(np.log(cityblock(vector1, vector2)+1)),
        np.nan_to_num(jaccard(vector1, vector2)),
        np.nan_to_num(canberra(vector1, vector2)),
        np.nan_to_num(euclidean(vector1, vector2)),
        np.nan_to_num(minkowski(vector1, vector2,3)),
        np.nan_to_num(braycurtis(vector1, vector2)),
        np.nan_to_num(hamming(vector1, vector2)),
        np.nan_to_num(kulsinski(vector1, vector2)),
        np.nan_to_num(chebyshev(vector1, vector2)),
        np.nan_to_num(dice(vector1, vector2)),
        np.nan_to_num(yule(vector1, vector2)),
        np.nan_to_num(sokalmichener(vector1, vector2)),
        np.nan_to_num(russellrao(vector1, vector2)),
        np.nan_to_num(rogerstanimoto(vector1, vector2))
    ]

#one_pair [2,100]
def get_one_pair_vector_distance(one_pair):
    vector1 = one_pair[0]
    vector2 = one_pair[1]
    return get_two_vector_distance(vector1, vector2)

temp_columns = ["cosine", "cityblock", "jaccard", "canberra",
                "euclidean", "minkowski", "braycurtis", "hamming",
                "kulsinski", "chebyshev","dice","yule",
                "sokalmichener","russellrao","rogerstanimoto"]

from fuzzywuzzy import fuzz
from jellyfish import jaro_distance, jaro_winkler
print("import fuzz success")

def get_one_pair_text_distance(one_pair_string):
    one_string1 = one_pair_string[0]
    one_string2 = one_pair_string[1]
    return get_two_text_distance(one_string1,one_string2)

def LD(s,t):
    # s = ' ' + s
    # t = ' ' + t
    d = {}
    S = len(s)
    T = len(t)
    # print(S)
    # print(T)
    for i in range(S):
        d[i, 0] = i
    for j in range (T):
        d[0, j] = j
    for j in range(1,T):
        for i in range(1,S):
            # print(s[i])
            # print(t[j])
            if s[i] == t[j]:
                d[i, j] = d[i-1, j-1]
            else:
                d[i, j] = min(d[i-1, j], d[i, j-1], d[i-1, j-1]) + 1
    return d[S-1, T-1]

def get_two_text_distance(text1,text2):
    if len(text1)==0 or len(text2)==0:
        return [0]*8
    return [
        fuzz.ratio(text1, text2) / 100,
        fuzz.partial_ratio(text1, text2) / 100,
        fuzz.token_sort_ratio(text1, text2) / 100,
        fuzz.token_set_ratio(text1, text2) / 100,
        fuzz.partial_token_sort_ratio(text1, text2) / 100,
        jaro_distance(text1, text2),
        jaro_winkler(text1, text2),
        LD(text1,text2) / (len(text1)+len(text2)),
    ]

def get_two_token_list_distance(token_list1, token_list2):
    if len(token_list1)==0 or len(token_list2)==0:
        return [0]*6
    return [
        fuzz.ratio(token_list1, token_list2) / 100,
        fuzz.partial_ratio(token_list1, token_list2) / 100,
        fuzz.token_sort_ratio(token_list1, token_list2) / 100,
        fuzz.token_set_ratio(token_list1, token_list2) / 100,
        fuzz.partial_token_sort_ratio(token_list1, token_list2) / 100,
        LD(token_list1, token_list2) / (len(token_list1) + len(token_list2)),
    ]

def get_one_pair_token_distance(one_pair_token):
    text1 = ' '.join(one_pair_token[0])
    text2 = ' '.join(one_pair_token[1])
    return get_two_text_distance(text1,text2)

def get_one_pair_token_distance2(one_pair_token):
    return get_two_token_list_distance(one_pair_token[0],one_pair_token[1])

temp_columns2 = ["fuzz_ratio_text", "fuzz_partial_ratio_text", "fuzz_token_sort_ratio_text",
                 "fuzz_token_set_ratio_text","fuzz_partial_token_sort_ratio_text",
                 "jaro_distance_text","jaro_winkler_text","levenshtein_distance_text"]

temp_columns3 = ["fuzz_ratio_words", "fuzz_partial_ratio_words", "fuzz_token_sort_ratio_words",
                 "fuzz_token_set_ratio_words","fuzz_partial_token_sort_ratio_words"
                 ,"levenshtein_distance_words"]